package com.cloud.shopping.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.cloud.shopping.search.mapper.SkuSearchMapper;
import com.cloud.shopping.search.model.SkuEs;
import com.cloud.shopping.search.service.SkuSearchService;
import com.cloud.shopping.search.tool.HighlightResultMapper;
import com.cloud.shopping.tool.PageInfo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author John.zhang
 * @version Id: SkuSearchServiceImpl, v 1.0 2020/12/31 11:00 ZhiYong Exp $
 */

@Service
public class SkuSearchServiceImpl implements SkuSearchService {

    @Resource
    private SkuSearchMapper skuSearchMapper;

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;


    @Override
    public Map<String, Object> search(Map<String, Object> searchMap) {
        //QueryBuilder->构建搜索条件
        NativeSearchQueryBuilder queryBuilder = queryBuilder(searchMap);
        //分组搜索调用
        group(queryBuilder, searchMap);

        //1.设置高亮信息   关键词前（后）面的标签、设置高亮域
        HighlightBuilder.Field field = new HighlightBuilder
                //根据指定的域进行高亮查询
                .Field("name")
                //关键词高亮前缀
                .preTags("<span style=\"color:red;\">")
                //高亮关键词后缀
                .postTags("</span>")
                //碎片长度
                .fragmentSize(100);
        queryBuilder.withHighlightFields(field);

        //2.将非高亮数据替换成高亮数据
        //默认查询
        //Page<SkuEs> page = skuSearchMapper.search(queryBuilder.build());
        //分组查询
        //AggregatedPage<SkuEs> page = (AggregatedPage<SkuEs>) skuSearchMapper.search(queryBuilder.build());
        AggregatedPage<SkuEs> page = elasticsearchRestTemplate.queryForPage(queryBuilder.build(), SkuEs.class, new HighlightResultMapper());

        //获取结果集：集合列表、总记录数
        Map<String, Object> resultMap = new HashMap<>(16);
        //分组数据解析
        parseGroup(page.getAggregations(), resultMap);
        //动态属性解析
        attrParse(resultMap);
        List<SkuEs> list = page.getContent();
        resultMap.put("list", list);
        resultMap.put("totalElements", page.getTotalElements());

        // 创建分页对象
        int currentPage = queryBuilder.build().getPageable().getPageNumber() + 1;
        PageInfo pageInfo = new PageInfo(page.getTotalElements(), currentPage, 5);
        resultMap.put("pageInfo", pageInfo);

        return resultMap;
    }

    @Override
    public void add(SkuEs skuEs) {
        String skuAttribute = skuEs.getSkuAttribute();
        if (!StringUtils.isEmpty(skuAttribute)) {
            skuEs.setAttrMap(JSON.parseObject(skuAttribute, Map.class));
        }
        skuSearchMapper.save(skuEs);
    }

    @Override
    public void delete(String id) {
        skuSearchMapper.deleteById(id);
    }

    /**
     * 将返回的动态属性信息合并成Map对象
     *
     * @param searchMap searchMap
     */
    public void attrParse(Map<String, Object> searchMap) {
        //先获取attrMaps
        Object attrMaps = searchMap.get("attrMaps");
        if (attrMaps != null) {
            //集合数据
            List<String> groupList = (List<String>) attrMaps;

            //定义一个集合Map<String,Set<String>>,存储所有汇总数据
            Map<String, Set<String>> allMaps = new HashMap<>(16);

            //循环集合
            for (String attr : groupList) {
                if (StringUtils.isEmpty(attr)) {
                    continue;
                }
                Map<String, String> attrMap = JSON.parseObject(attr, Map.class);

                for (Map.Entry<String, String> entry : attrMap.entrySet()) {
                    //获取每条记录,将记录转成Map   就业薪资    学习费用
                    String key = entry.getKey();
                    Set<String> values = allMaps.get(key);
                    if (values == null) {
                        values = new HashSet<>();
                    }
                    values.add(entry.getValue());
                    //覆盖之前的数据
                    allMaps.put(key, values);
                }
            }
            //覆盖之前的attrMaps
            searchMap.put("attrMaps", allMaps);
        }
    }

    /**
     * 分组结果解析
     *
     * @param aggregations aggregations
     * @param resultMap    resultMap
     */
    public void parseGroup(Aggregations aggregations, Map<String, Object> resultMap) {
        if (aggregations != null) {
            for (Aggregation aggregation : aggregations) {
                //强转ParsedStringTerms
                ParsedStringTerms terms = (ParsedStringTerms) aggregation;

                //循环结果集对象
                List<String> values = new ArrayList<>();
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    values.add(bucket.getKeyAsString());
                }
                //名字
                String key = aggregation.getName();
                resultMap.put(key, values);
            }
        }
    }

    /**
     * 分组查询
     *
     * @param queryBuilder queryBuilder
     * @param searchMap    searchMap
     */
    public void group(NativeSearchQueryBuilder queryBuilder, Map<String, Object> searchMap) {
        //用户如果没有输入分类条件，则需要将分类搜索出来，作为条件提供给用户
        String categoryField = "category";
        if (StringUtils.isEmpty(searchMap.get(categoryField))) {
            queryBuilder.addAggregation(
                    AggregationBuilders
                            //别名，类似Map的key
                            .terms("categoryList")
                            //根据categoryName域进行分组
                            .field("categoryName.keyword")
                            //分组结果显示100个
                            .size(100)
            );
        }
        //用户如果没有输入品牌条件，则需要将品牌搜索出来，作为条件提供给用户
        String brandField = "brand";
        if (StringUtils.isEmpty(searchMap.get(brandField))) {
            queryBuilder.addAggregation(
                    AggregationBuilders
                            //别名，类似Map的key
                            .terms("brandList")
                            //根据brandName域进行分组
                            .field("brandName.keyword")
                            //分组结果显示100个
                            .size(100)
            );
        }
        //属性分组查询
        queryBuilder.addAggregation(
                AggregationBuilders
                        //别名，类似Map的key
                        .terms("attrMaps")
                        //根据skuAttribute域进行分组
                        .field("skuAttribute.keyword")
                        //分组结果显示1000个
                        .size(1000)
        );
    }

    /**
     * 搜索条件构建
     *
     * @param searchMap searchMap
     * @return NativeSearchQueryBuilder
     */
    public NativeSearchQueryBuilder queryBuilder(Map<String, Object> searchMap) {
        //默认只能支持单个条件的查询
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();

        //组合查询对象(用于多个条件的组合查询)
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //判断关键词是否为空，不为空，则设置条件
        if (searchMap != null && searchMap.size() > 0) {
            //关键词条件
            Object keywords = searchMap.get("keywords");
            if (!StringUtils.isEmpty(keywords)) {
                //默认查询
                //builder.withQuery(QueryBuilders.termQuery("name", keywords.toString()));
                boolQueryBuilder.must(QueryBuilders.termQuery("name", keywords.toString()));
            }

            //分类查询
            Object category = searchMap.get("category");
            if (!StringUtils.isEmpty(category)) {
                boolQueryBuilder.must(QueryBuilders.termQuery("categoryName", category.toString()));
            }

            //品牌查询
            Object brand = searchMap.get("brand");
            if (!StringUtils.isEmpty(brand)) {
                boolQueryBuilder.must(QueryBuilders.termQuery("brandName", brand.toString()));
            }

            //价格区间查询  price=0-500元  500-1000元  1000元以上
            Object price = searchMap.get("price");
            if (!StringUtils.isEmpty(price)) {
                //价格区间
                String[] prices = price.toString().replace("元", "").replace("以上", "").split("-");
                //price>x
                boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gt(Integer.valueOf(prices[0])));
                //price<=y
                int length = 2;
                if (prices.length == length) {
                    boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(Integer.valueOf(prices[1])));
                }
            }

            //动态属性查询
            for (Map.Entry<String, Object> entry : searchMap.entrySet()) {
                //以attr_开始，动态属性  attr_网络：移动5G
                if (entry.getKey().startsWith("attr_")) {
                    String key = "attrMap." + entry.getKey().replaceFirst("attr_", "") + ".keyword";
                    boolQueryBuilder.must(QueryBuilders.termQuery(key, entry.getValue().toString()));
                }
            }

            //排序
            Object sField = searchMap.get("sField");
            Object sm = searchMap.get("sm");
            if (!StringUtils.isEmpty(sField) && !StringUtils.isEmpty(sm)) {
                builder.withSort(
                        //指定排序域
                        SortBuilders.fieldSort(sField.toString())
                                //排序方式
                                .order(SortOrder.valueOf(sm.toString()))
                );
            }
        }

        //分页查询
        builder.withPageable(PageRequest.of(currentPage(searchMap), 5));
        return builder.withQuery(boolQueryBuilder);
    }

    /**
     * 分页参数
     *
     * @param searchMap searchMap
     * @return int
     */
    public int currentPage(Map<String, Object> searchMap) {
        try {
            Object page = searchMap.get("page");
            return Integer.parseInt(page.toString()) - 1;
        } catch (Exception e) {
            return 0;
        }
    }

}
